package distributedbank;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * Oracle is the failure detector. It keeps one list of servers for each bank
 * branch. It can destroy a server or recover a destroyed server. It notify all
 * servers when some server is bad.
 */
public class Oracle implements ActionListener
{
    private static int width = 600;

    private static int height = 300;

    private static List<Integer> serverChain1;

    private static List<Integer> serverChain2;

    private static List<Integer> serverChain3;

    private static List<Integer> serverChain4;

    private JFrame frame;

    private JLabel branch1Label;

    private JLabel branch2Label;

    private JLabel branch3Label;

    private JLabel branch4Label;

    private JLabel branch1Server1Label;

    private JLabel branch1Server2Label;

    private JLabel branch1Server3Label;

    private JLabel branch2Server1Label;

    private JLabel branch2Server2Label;

    private JLabel branch2Server3Label;

    private JLabel branch3Server1Label;

    private JLabel branch3Server2Label;

    private JLabel branch3Server3Label;

    private JLabel branch4Server1Label;

    private JLabel branch4Server2Label;

    private JLabel branch4Server3Label;

    // enable/disable, branch, servers
    private JButton serverControl[][][] = new JButton[2][4][3];

    // a disabled counter for each branch, cannot exceed 2
    private int disabledCounter[] = new int[4];

    private int disabledServer[] = new int[4];

    private JPanel branch1Panel;

    private JPanel branch2Panel;

    private JPanel branch3Panel;

    private JPanel branch4Panel;

    private JPanel branch1ServerPanel;

    private JPanel branch2ServerPanel;

    private JPanel branch3ServerPanel;

    private JPanel branch4ServerPanel;

    @SuppressWarnings("serial")
    public Oracle() {
        serverChain1 = new ArrayList<Integer>();
        serverChain2 = new ArrayList<Integer>();
        serverChain3 = new ArrayList<Integer>();
        serverChain4 = new ArrayList<Integer>();

        frame = new JFrame( "ORACLE" );
        branch1Label = new JLabel( "Branch 1" );
        branch2Label = new JLabel( "Branch 2" );
        branch3Label = new JLabel( "Branch 3" );
        branch4Label = new JLabel( "Branch 4" );
        branch1Label.setHorizontalAlignment( JLabel.CENTER );
        branch2Label.setHorizontalAlignment( JLabel.CENTER );
        branch3Label.setHorizontalAlignment( JLabel.CENTER );
        branch4Label.setHorizontalAlignment( JLabel.CENTER );

        branch1Server1Label = new JLabel( "Server 1" );
        branch1Server2Label = new JLabel( "Server 2" );
        branch1Server3Label = new JLabel( "Server 3" );
        branch2Server1Label = new JLabel( "Server 1" );
        branch2Server2Label = new JLabel( "Server 2" );
        branch2Server3Label = new JLabel( "Server 3" );
        branch3Server1Label = new JLabel( "Server 1" );
        branch3Server2Label = new JLabel( "Server 2" );
        branch3Server3Label = new JLabel( "Server 3" );
        branch4Server1Label = new JLabel( "Server 1" );
        branch4Server2Label = new JLabel( "Server 2" );
        branch4Server3Label = new JLabel( "Server 3" );
        branch1Server1Label.setHorizontalAlignment( JLabel.CENTER );
        branch1Server2Label.setHorizontalAlignment( JLabel.CENTER );
        branch1Server3Label.setHorizontalAlignment( JLabel.CENTER );
        branch2Server1Label.setHorizontalAlignment( JLabel.CENTER );
        branch2Server2Label.setHorizontalAlignment( JLabel.CENTER );
        branch2Server3Label.setHorizontalAlignment( JLabel.CENTER );
        branch3Server1Label.setHorizontalAlignment( JLabel.CENTER );
        branch3Server2Label.setHorizontalAlignment( JLabel.CENTER );
        branch3Server3Label.setHorizontalAlignment( JLabel.CENTER );
        branch4Server1Label.setHorizontalAlignment( JLabel.CENTER );
        branch4Server2Label.setHorizontalAlignment( JLabel.CENTER );
        branch4Server3Label.setHorizontalAlignment( JLabel.CENTER );

        // 0 for disabled, 1 for enabled buttons
        for( int i = 0; i < 2; i++ ) {
            for( int j = 0; j < 4; j++ ) {
                for( int k = 0; k < 3; k++ ) {
                    final int branchId = j;
                    final int serverId = k;
                    if( i == 0 ) {
                        serverControl[i][j][k] = new JButton(
                                new AbstractAction( "Disable" )
                                {
                                    public final void actionPerformed(
                                            ActionEvent e ) {
                                        disablePressed( branchId, serverId );
                                    }
                                } );
                        serverControl[i][j][k].setText( "Disable" );
                    } else {
                        serverControl[i][j][k] = new JButton(
                                new AbstractAction( "Enable" )
                                {
                                    public final void actionPerformed(
                                            ActionEvent e ) {
                                        enablePressed( branchId, serverId );
                                    }
                                } );
                        serverControl[i][j][k].setText( "Enable" );
                        // initially, all servers are enabled, set those buttons
                        // for false
                        serverControl[i][j][k].setEnabled( false );
                    }
                }
            }
        }

        branch1Panel = new JPanel();
        branch2Panel = new JPanel();
        branch3Panel = new JPanel();
        branch4Panel = new JPanel();

        branch1ServerPanel = new JPanel();
        branch2ServerPanel = new JPanel();
        branch3ServerPanel = new JPanel();
        branch4ServerPanel = new JPanel();

        frame.setSize( width, height );
        frame.setVisible( true );
        frame.setResizable( false );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.setLayout( new GridLayout( 2, 2 ) );
        frame.add( branch1Panel );
        frame.add( branch2Panel );
        frame.add( branch3Panel );
        frame.add( branch4Panel );

        branch1Panel.setLayout( new BorderLayout() );
        branch1Panel.add( "North", branch1Label );
        branch1Panel.add( branch1ServerPanel );
        branch1ServerPanel.setLayout( new GridLayout( 3, 3 ) );

        branch1ServerPanel.add( branch1Server1Label );
        branch1ServerPanel.add( serverControl[1][0][0] );
        branch1ServerPanel.add( serverControl[0][0][0] );
        branch1ServerPanel.add( branch1Server2Label );
        branch1ServerPanel.add( serverControl[1][0][1] );
        branch1ServerPanel.add( serverControl[0][0][1] );
        branch1ServerPanel.add( branch1Server3Label );
        branch1ServerPanel.add( serverControl[1][0][2] );
        branch1ServerPanel.add( serverControl[0][0][2] );

        branch2Panel.setLayout( new BorderLayout() );
        branch2Panel.add( "North", branch2Label );
        branch2Panel.add( branch2ServerPanel );
        branch2ServerPanel.setLayout( new GridLayout( 3, 3 ) );
        branch2ServerPanel.add( branch2Server1Label );
        branch2ServerPanel.add( serverControl[1][1][0] );
        branch2ServerPanel.add( serverControl[0][1][0] );
        branch2ServerPanel.add( branch2Server2Label );
        branch2ServerPanel.add( serverControl[1][1][1] );
        branch2ServerPanel.add( serverControl[0][1][1] );
        branch2ServerPanel.add( branch2Server3Label );
        branch2ServerPanel.add( serverControl[1][1][2] );
        branch2ServerPanel.add( serverControl[0][1][2] );

        branch3Panel.setLayout( new BorderLayout() );
        branch3Panel.add( "North", branch3Label );
        branch3Panel.add( branch3ServerPanel );
        branch3ServerPanel.setLayout( new GridLayout( 3, 3 ) );
        branch3ServerPanel.add( branch3Server1Label );
        branch3ServerPanel.add( serverControl[1][2][0] );
        branch3ServerPanel.add( serverControl[0][2][0] );
        branch3ServerPanel.add( branch3Server2Label );
        branch3ServerPanel.add( serverControl[1][2][1] );
        branch3ServerPanel.add( serverControl[0][2][1] );
        branch3ServerPanel.add( branch3Server3Label );
        branch3ServerPanel.add( serverControl[1][2][2] );
        branch3ServerPanel.add( serverControl[0][2][2] );

        branch4Panel.setLayout( new BorderLayout() );
        branch4Panel.add( "North", branch4Label );
        branch4Panel.add( branch4ServerPanel );
        branch4ServerPanel.setLayout( new GridLayout( 3, 3 ) );
        branch4ServerPanel.add( branch4Server1Label );
        branch4ServerPanel.add( serverControl[1][3][0] );
        branch4ServerPanel.add( serverControl[0][3][0] );
        branch4ServerPanel.add( branch4Server2Label );
        branch4ServerPanel.add( serverControl[1][3][1] );
        branch4ServerPanel.add( serverControl[0][3][1] );
        branch4ServerPanel.add( branch4Server3Label );
        branch4ServerPanel.add( serverControl[1][3][2] );
        branch4ServerPanel.add( serverControl[0][3][2] );
    }

    private void enablePressed( int branchId, int serverId ) {
        if( disabledCounter[branchId]-- == 2 ) {
            serverControl[0][branchId][disabledServer[branchId]]
                    .setEnabled( true );
        }
        serverControl[1][branchId][serverId].setEnabled( false );
        serverControl[0][branchId][serverId].setEnabled( true );
        // no need to check, it cannot go below 0

        // TODO: do other stuff
    }

    private void disablePressed( int branchId, int serverId ) {
        serverControl[1][branchId][serverId].setEnabled( true );
        serverControl[0][branchId][serverId].setEnabled( false );

        if( ++disabledCounter[branchId] == 2 ) {
            for( int k = 0; k < 3; k++ )
                if( serverControl[0][branchId][k].isEnabled() ) {
                    disabledServer[branchId] = k;
                    serverControl[0][branchId][k].setEnabled( false );
                    break;
                }
        }

        // TODO: do other stuff
    }

    public static void main( String[] args ) {
        new Oracle();
    }

    @Override
    public void actionPerformed( ActionEvent e_ ) {
        // TODO Auto-generated method stub

    }
}
